"use strict";

/**
 * Manage Flickr service calls
 * @param {String} key API key
 * @param {String} secret API secret
 * @constructor
 */
function Flickr(key, secret)
{
	/** @type {Flickr} */
	var _this = this;
	/** Track number of calls to generate unique callback method name */
	var _callCount = 1;

	/**
	 * Get collection of Flickr sets and photos
	 * @param {function(Flickr.Tree)} callback method to call when collection is returned
	 */
	this.getCollection = function(callback)
	{
		call('collections.getTree', 'user_id', Enum.flickr.userID, function(r)
		{
			callback(r.collections);
		});
	};
	
	/**
	 * Creates new setObject or updates an existing one
	 * @param {String} id Flickr ID of the set
	 * @param {Array.<Enum.size>} imageSizes Image size optional parameters sent to service
	 * @param {function(Flickr.SetPhotos, Flickr.SetInfo)} callback Method to call after Flickr responds
	 * @param {Boolean} [alsoGetInfo = false] Whether to also call getInfo() for additional details
	 * @see http://www.flickr.com/services/api/flickr.photosets.getPhotos.html
	 * @see http://www.flickr.com/services/api/flickr.photos.getInfo.html
	 */
	this.getSet = function(id, imageSizes, callback, alsoGetInfo)
	{
		var type = 'photoset_id';
		
		call('photosets.getPhotos', type, id, function(r)
		{
			/** @type {Flickr.SetPhotos} */
			var photos = r.photoset;
			
			if (alsoGetInfo)
			{
				call('photosets.getInfo', type, id, function(r) { callback(photos, r.photoset);	});
			}
			else
			{
				callback(photos, null);
			}
		},
			imageSizes.concat(['description, date_taken', 'geo', 'last_update'])		// extras
		);
	};

	/**
	 * Get photo context
	 * @param {String} id Flickr photo ID
	 * @param {function(Flickr.PhotoMembership)} callback
	 * @see http://www.flickr.com/services/api/flickr.photos.getAllContexts.html
	 */
	this.getContext = function(id, callback)
	{
		call('photos.getAllContexts', 'photo_id', id, function(r) { callback(r.set); });
	};

	/**
	 * Get photo context
	 * @param {String} id Flickr photo ID
	 * @param {function(Flickr.PhotoExif.photo)} callback
	 * @see http://www.flickr.com/services/api/flickr.photos.getExif.html
	 */
	this.getEXIF = function(id, callback)
	{
		call('photos.getExif', 'photo_id', id, function(r) { callback(r.photo); });
	};

	/**
	 * Get photo sizes
	 * @param {String} id Flickr photo ID
	 * @param {function(Flickr.Size)} callback Method to call when Flickr responds
	 * @see http://www.flickr.com/services/api/flickr.photos.getSizes.html
	 */
	this.getSizes = function(id, callback)
	{
		call('photos.getSizes', 'photo_id', id, callback);
	};
	
//- private methods -----------------------------------------------------------

	/**
	 * Execute service call
	 * @param {String} method Name of Flickr API method to call
	 * @param {String} idType Type of Flickr ID whether photo, set, collection, etc.
	 * @param {String} id Flickr object ID
	 * @param {Function(FlickrResponse)} callback Method to call when service completes
	 * @param {Array.<String>} [extras] Additional fields to return from the service
	 * @see http://www.flickr.com/services/api/response.json.html
	 */
	function call(method, idType, id, callback, extras)
	{
		var jsonCallName = "trailImageCallback" + (_callCount++);

		$.ajax({
			url: Enum.flickr.api,
			cache: false,
			dataType: 'jsonp',
			jsonp: false,
			data: parameterize(method, idType, id, jsonCallName, extras),
			jsonpCallback: jsonCallName,			// unique name to avoid callback collisions
			beforeSend: function(xhr, settings) { xhr.overrideMimeType('application/json');	},
			success: callback,
			error: function(xhr, status) { alert(status); }
		});
	}

	/**
	 * Setup standard parameters
	 * @param {String} method Name of flickr API method to call
	 * @param {String} idType The type of ID whether photo, set or other
	 * @param {String} id ID of the flickr object
	 * @param {String} jsonCallName
	 * @param {Array.<String>} [extras] Additional fields to return
	 * @return {Object.<String>}
	 */
	function parameterize(method, idType, id, jsonCallName, extras)
	{
		var args =
		{
			'api_key': Enum.flickr.key,
			'format': 'json',
			'jsoncallback': jsonCallName,
			'method': 'flickr.' + method
		};

		args[idType] = id;

		if (extras) { args.extras = extras.toString(); }

		return args;
	}
}